<template>
	<div class="scTable" :style="{ height: _height }" ref="scTableMain" v-loading="loading">
		<div class="scTable-table" :style="{ height: _table_height }">
			<el-table
				ref="scTable"
				v-bind="$attrs"
				:data="tableData"
				:row-key="props.rowKey"
				:key="toggleIndex"
				:height="props.height == 'auto' ? null : '100%'"
				:size="config.size"
				:border="config.border"
				:stripe="config.stripe"
				:summary-method="props.remoteSummary ? remoteSummaryMethod : props.summaryMethod"
				@sort-change="sortChange"
				@filter-change="filterChange"
			>
				<slot></slot>
				<template v-for="(item, index) in userColumn" :key="index">
					<el-table-column
						v-if="!item.hide"
						:column-key="item.prop"
						:label="item.label"
						:prop="item.prop"
						:width="item.width"
						:sortable="item.sortable"
						:fixed="item.fixed"
						:filters="item.filters"
						:filter-method="props.remoteFilter || !item.filters ? null : filterHandler"
						:show-overflow-tooltip="item.showOverflowTooltip"
					>
						<template #default="scope">
							<slot :name="item.prop" v-bind="scope">
								{{ scope.row[item.prop] }}
							</slot>
						</template>
					</el-table-column>
				</template>
				<template #empty>
					<el-empty :description="emptyText" :image-size="100"></el-empty>
				</template>
			</el-table>
		</div>
		<div class="scTable-page" v-if="!props.hidePagination || !props.hideDo">
			<slot name="operation"></slot>
			<div class="scTable-pagination">
				<el-pagination
					v-if="!props.hidePagination"
					background
					size="small"
					:layout="props.paginationLayout"
					:total="total"
					:page-size="scPageSize"
					:page-sizes="props.pageSizes"	
					v-model:currentPage="currentPage"
					@current-change="paginationChange"
					@update:page-size="pageSizeChange"
				></el-pagination>
			</div>
			<div class="scTable-do" v-if="!props.hideDo">
				<el-button v-if="!props.hideRefresh" @click="refresh" icon="el-icon-refresh" circle style="margin-left: 15px"></el-button>
				<el-popover v-if="props.column" placement="top" :title="$t('table.column')" :width="500" trigger="click" :hide-after="0" @show="customColumnShow = true" @after-leave="customColumnShow = false">
					<template #reference>
						<el-button icon="el-icon-set-up" circle style="margin-left: 15px"></el-button>
					</template>
					<columnSetting v-if="customColumnShow" ref="columnSettingRef" @userChange="columnSettingChange" @save="columnSettingSave" @back="columnSettingBack" :column="userColumn"></columnSetting>
				</el-popover>
				<el-popover v-if="!props.hideSetting" placement="top" :title="$t('table.setting')" :width="400" trigger="click" :hide-after="0">
					<template #reference>
						<el-button icon="el-icon-setting" circle style="margin-left: 15px"></el-button>
					</template>
					<el-form label-width="80px" label-position="left">
						<el-form-item :label="$t('table.size')">
							<el-radio-group v-model="config.size" size="small" @change="configSizeChange">
								<el-radio-button value="large">{{ $t('table.large') }}</el-radio-button>
								<el-radio-button value="default">{{ $t('table.default') }}</el-radio-button>
								<el-radio-button value="small">{{ $t('table.small') }}</el-radio-button>
							</el-radio-group>
						</el-form-item>
						<el-form-item :label="$t('table.style')">
							<el-checkbox v-model="config.border" :label="$t('table.border')"></el-checkbox>
							<el-checkbox v-model="config.stripe" :label="$t('table.stripe')"></el-checkbox>
						</el-form-item>
					</el-form>
				</el-popover>
			</div>
		</div>
	</div>
</template>
<script setup lang="ts">
	// 组件懒加载
	const columnSetting = defineAsyncComponent(() => import('./columnSetting.vue'))
	// 定义组件的属性类型和默认值
	const props = defineProps({
		// 表格名称
		tableName: { type: String, default: '' },
		// API 对象，用于数据请求
		apiObj: { type: Object, default: () => {} },
		// 请求参数
		params: { type: Object, default: () => ({}) },
		// 表格数据
		data: { type: Object, default: () => {} },
		// 表格高度
		height: { type: [String, Number], default: '100%' },
		// 表格尺寸
		size: { type: String, default: 'default' },
		// 是否显示边框
		border: { type: Boolean, default: false },
		// 是否显示斑马纹
		stripe: { type: Boolean, default: false },
		// 每页条数
		pageSize: { type: Number, default: table.pageSize },
		// 可选的每页条数
		pageSizes: { type: Array, default: table.pageSizes },
		// 行的唯一标识
		rowKey: { type: String, default: '' },
		// 自定义汇总方法
		summaryMethod: { type: Function, default: null },
		// 列配置
		column: { type: Object, default: () => {} },
		// 是否使用远程排序
		remoteSort: { type: Boolean, default: false },
		// 是否使用远程过滤
		remoteFilter: { type: Boolean, default: false },
		// 是否使用远程汇总
		remoteSummary: { type: Boolean, default: false },
		// 是否隐藏分页
		hidePagination: { type: Boolean, default: false },
		// 是否隐藏操作区
		hideDo: { type: Boolean, default: false },
		// 是否隐藏刷新按钮
		hideRefresh: { type: Boolean, default: false },
		// 是否隐藏设置按钮
		hideSetting: { type: Boolean, default: false },
		// 分页布局
		paginationLayout: { type: String, default: table.paginationLayout }
	})
	// 定义要触发的事件
	const emit = defineEmits(['dataChange'])
	// 响应式引用，每页数据条数
	const scPageSize = ref(props.pageSize)
	// 组件激活状态
	const isActivat = ref(true)
	// 空表格文本
	const emptyText = ref(lang.global.t('table.empty'))
	// 切换索引
	const toggleIndex = ref(0)
	// 表格数据
	const tableData = ref<any>([])
	// 数据总数
	const total = ref(0)
	// 当前页码
	const currentPage = ref(1)
	// 排序字段
	const prop = ref<string | null>(null)
	// 排序方式
	const order = ref<string | null>(null)
	// 加载状态
	const loading = ref(false)
	// 表格请求参数
	const tableParams = ref(props.params)
	// 用户自定义列
	const userColumn = ref<any>([])
	// 自定义列弹出框显示状态
	const customColumnShow = ref(false)
	// 汇总数据
	const summary = ref<any>({})
	// 配置项
	const config = reactive({
		// 尺寸
		size: props.size,
		// 边框
		border: props.border,
		// 斑马纹
		stripe: props.stripe
	})
	// 表格主容器引用
	const scTableMain = ref()
	// 表格引用
	const scTable = ref()
	// 列设置组件引用
	const columnSettingRef = ref()
	// 表格高度计算
	const _height = computed(() => (Number(props.height) ? Number(props.height) + 'px' : props.height))
	// 表格内容区高度计算
	const _table_height = computed(() => (props.hidePagination && props.hideDo ? '100%' : 'calc(100% - 50px)'))
	// 监听数据变化，更新表格数据
	watch(
		() => props.data,
		() => {
			// 更新表格数据
			tableData.value = props.data
			// 更新数据总数
			total.value = tableData.value.length
		}
	)
	// 监听 API 对象变化，更新请求参数并刷新数据
	watch(
		() => props.apiObj,
		() => {
			// 更新请求参数
			tableParams.value = props.params
			// 刷新数据
			refresh()
		}
	)
	// 监听列配置变化，更新用户自定义列
	watch(
		() => props.column,
		() => (userColumn.value = props.column)
	)
	// 组件挂载时执行的逻辑
	onMounted(() => {
		if (props.column) {
			// 获取自定义列
			getCustomColumn()
		} else {
			// 设置用户自定义列
			userColumn.value = props.column
		}
		if (props.apiObj) {
			// 获取数据
			getData()
		} else if (props.data) {
			// 设置表格数据
			tableData.value = props.data
			// 更新数据总数
			total.value = tableData.value.length
		}
	})
	// 组件激活时触发的逻辑
	onActivated(() => {
		if (!isActivat.value) {
			// 重新布局表格
			scTable.value.doLayout()
		}
	})
	// 组件非激活时触发的逻辑
	onDeactivated(() => {
		// 更新激活状态
		isActivat.value = false
	})
	// 获取自定义列配置
	const getCustomColumn = async () => {
		// 获取列设置
		const column = await table.columnSettingGet(props.tableName, props.column)
		// 设置用户自定义列
		userColumn.value = column
	}
	// 获取表格数据
	const getData = async () => {
		// 开始加载
		loading.value = true
		var reqData = {
			// 当前页码
			[table.request.page]: currentPage.value,
			// 每页条数
			[table.request.pageSize]: scPageSize.value,
			// 排序字段
			[table.request.prop]: prop.value,
			// 排序方式
			[table.request.order]: order.value
		}
		if (props.hidePagination) {
			// 如果隐藏分页，删除当前页码
			delete reqData[table.request.page]
			// 删除每页条数
			delete reqData[table.request.pageSize]
		}
		// 合并请求参数
		Object.assign(reqData, tableParams.value)
		try {
			// 发送请求
			const res = await props.apiObj.get(reqData)
			// 解析数据
			const response = table.parseData(res)
			if (response.code != table.successCode) {
				// 停止加载
				loading.value = false
				// 更新空表格文本
				emptyText.value = response.msg
			} else {
				// 重置空表格文本
				emptyText.value = lang.global.t('table.empty')
				if (props.hidePagination) {
					// 更新表格数据
					tableData.value = response.data || []
				} else {
					// 更新表格数据
					tableData.value = response.rows || []
				}
				// 更新数据总数
				total.value = response.total || 0
				// 更新汇总数据
				summary.value = response.summary || {}
				// 停止加载
				loading.value = false
			}
			// 设置滚动条回到顶部
			scTable.value.setScrollTop(0)
			// 触发数据变化事件
			emit('dataChange', res, tableData)
		} catch (error: any) {
			// 停止加载
			loading.value = false
			// 更新空表格文本
			emptyText.value = error.statusText || lang.global.t('table.dataErr')
			return false
		}
	}
	// 分页改变事件处理
	const paginationChange = () => getData()
	// 每页条数改变事件处理
	const pageSizeChange = (size: number) => ((scPageSize.value = size), getData())
	// 刷新表格数据
	const refresh = () => (scTable.value.clearSelection(), getData())
	// 更新表格数据
	const upData = (params: any, page = 1) => {
		// 更新当前页码
		currentPage.value = page
		// 清空选中
		scTable.value.clearSelection()
		// 合并参数
		Object.assign(tableParams.value, params || {})
		// 获取数据
		getData()
	}
	// 重新加载表格数据
	const reload = (params: any, page = 1) => {
		// 更新当前页码
		currentPage.value = page
		// 更新请求参数
		tableParams.value = params || {}
		// 清空选中
		scTable.value.clearSelection()
		// 清空排序
		scTable.value.clearSort()
		// 清空过滤
		scTable.value.clearFilter()
		// 获取数据
		getData()
	}
	// 列设置变化事件处理
	const columnSettingChange = (column: any) => ((userColumn.value = column), (toggleIndex.value += 1))
	// 保存列设置
	const columnSettingSave = async (column: any) => {
		// 标记为正在保存
		columnSettingRef.value.isSave = true
		try {
			// 调用表格的列设置保存方法，传入表名和列配置
			await table.columnSettingSave(props.tableName, column)
		} catch (error) {
			// 如果发生错误，显示错误消息
			ElMessage.error(lang.global.t('table.saveError'))
		}
		// 显示保存成功消息
		ElMessage.success(lang.global.t('table.saveSuccess'))
		// 重置保存标记
		columnSettingRef.value.isSave = false
	}
	// 恢复列设置
	const columnSettingBack = async () => {
		// 标记为正在恢复
		columnSettingRef.value.isSave = true
		try {
			// 调用表格的列设置重置方法，获取默认列配置
			const column = await table.columnSettingReset(props.tableName, props.column)
			// 更新用户列配置
			userColumn.value = column
			// 深拷贝更新后的列配置
			columnSettingRef.value.usercolumn = JSON.parse(JSON.stringify(userColumn.value || []))
		} catch (error) {
			// 如果发生错误，显示错误消息
			ElMessage.error(lang.global.t('table.resetErr'))
		}
		// 重置保存标记
		columnSettingRef.value.isSave = false
	}
	// 排序变化处理
	const sortChange = (obj: { column: any; prop: string | null; order: string | null }) => {
		// 如果不支持远程排序，直接返回
		if (!props.remoteSort) {
			return false
		}
		if (obj.column && obj.prop) {
			// 更新排序字段
			prop.value = obj.prop
			// 更新排序方式
			order.value = obj.order
		} else {
			// 清空排序字段
			prop.value = null
			// 清空排序方式
			order.value = null
		}
		// 重新获取数据
		getData()
	}
	// 过滤器处理
	const filterHandler = (value: any, row: { [x: string]: any }, column: { property: any }) => {
		// 获取列属性
		const property = column.property
		// 返回是否匹配过滤条件
		return row[property] === value
	}
	// 过滤变化处理
	const filterChange = (filters: any) => {
		// 如果不支持远程过滤，直接返回
		if (!props.remoteFilter) {
			return false
		}
		Object.keys(filters).forEach((key) => {
			// 将过滤值转换为字符串
			filters[key] = filters[key].join(',')
		})
		// 更新数据
		upData(filters)
	}
	// 远程汇总方法
	const remoteSummaryMethod = (param: { columns: any }) => {
		const { columns } = param
		const sums: any[] = []
		columns.forEach((column: { property: string | number }, index: number) => {
			if (index === 0) {
				// 第一列显示总计
				sums[index] = lang.global.t('common.total')
				return
			}
			// 获取对应列的汇总值
			const values = summary.value[column.property]
			if (values) {
				// 如果有汇总值，添加到数组中
				sums[index] = values
			} else {
				// 否则为空
				sums[index] = ''
			}
		})
		// 返回汇总值数组
		return sums
	}
	// 配置大小变化处理
	const configSizeChange = () => {
		// 调整表格布局
		scTable.value.doLayout()
	}
	// 在表格前添加行
	const unshiftRow = (row: any) => tableData.value.unshift(row)
	// 在表格后添加行
	const pushRow = (row: any) => tableData.value.push(row)
	// 更新特定行的值
	const updateKey = (row: { [x: string]: any }, rowKey = props.rowKey) => {
		tableData.value
			.filter((item: { [x: string]: any }) => item[rowKey] === row[rowKey])
			.forEach((item: any) => {
				// 更新匹配的行
				Object.assign(item, row)
			})
	}
	// 更新特定索引的行
	const updateIndex = (row: any, index: string | number) => Object.assign(tableData.value[index], row)
	// 删除特定索引的行
	const removeIndex = (index: any) => tableData.value.splice(index, 1)
	// 删除多个索引的行
	const removeIndexes = (indexes = []) => {
		indexes.forEach((index) => {
			// 删除每个指定索引的行
			tableData.value.splice(index, 1)
		})
	}
	// 根据键值删除行
	const removeKey = (key: any, rowKey = props.rowKey) => {
		tableData.value.splice(
			// 删除找到的行
			tableData.value.findIndex((item: { [x: string]: any }) => item[rowKey] === key),
			1
		)
	}
	// 根据多个键值删除行
	const removeKeys = (keys = [], rowKey = props.rowKey) => {
		keys.forEach((key) => {
			tableData.value.splice(
				// 删除找到的行
				tableData.value.findIndex((item: { [x: string]: any }) => item[rowKey] === key),
				1
			)
		})
	}
	// 清空选中的行
	const clearSelection = () => scTable.value.clearSelection()
	// 切换行选择状态
	const toggleRowSelection = (row: any, selected: any) => scTable.value.toggleRowSelection(row, selected)
	// 切换所有行的选择状态
	const toggleAllSelection = () => scTable.value.toggleAllSelection()
	// 切换行的展开状态
	const toggleRowExpansion = (row: any, expanded: any) => scTable.value.toggleRowExpansion(row, expanded)
	// 设置当前选中的行
	const setCurrentRow = (row: any) => scTable.value.setCurrentRow(row)
	// 清空排序
	const clearSort = () => scTable.value.clearSort()
	// 清空指定列的过滤
	const clearFilter = (columnKey: any) => scTable.value.clearFilter(columnKey)
	// 调整表格布局
	const doLayout = () => scTable.value.doLayout()
	// 执行排序
	const sort = (prop: any, order: any) => scTable.value.sort(prop, order)
	// 将公共方法暴露给外部
	defineExpose({
		// 更新数据的方法
		upData,
		// 刷新数据的方法
		refresh,
		// 重新加载数据的方法
		reload,
		// 表格数据
		tableData,
		// 在表格前添加行
		unshiftRow,
		// 在表格后添加行
		pushRow,
		// 更新特定行的值
		updateKey,
		// 更新特定索引的行
		updateIndex,
		// 删除特定索引的行
		removeIndex,
		// 删除多个索引的行
		removeIndexes,
		// 根据键值删除行
		removeKey,
		// 根据多个键值删除行
		removeKeys,
		// 清空选中的行
		clearSelection,
		// 切换行选择状态
		toggleRowSelection,
		// 切换所有行的选择状态
		toggleAllSelection,
		// 切换行的展开状态
		toggleRowExpansion,
		// 设置当前选中的行
		setCurrentRow,
		// 清空排序
		clearSort,
		// 清空指定列的过滤
		clearFilter,
		// 调整表格布局
		doLayout,
		// 执行排序
		sort
	})
</script>
<style lang="less" scoped>
	.scTable-table {
		height: calc(100% - 50px);
	}
	.scTable-page {
		height: 50px;
		display: flex;
		align-items: center;
		justify-content: space-between;
		padding: 0 15px;
	}
	.scTable-do {
		white-space: nowrap;
	}
	.scTable:deep(.el-table__footer) .cell {
		font-weight: bold;
	}
	.scTable:deep(.el-table__body-wrapper) .el-scrollbar__bar.is-horizontal {
		height: 12px;
		border-radius: 12px;
	}
	.scTable:deep(.el-table__body-wrapper) .el-scrollbar__bar.is-vertical {
		width: 12px;
		border-radius: 12px;
	}
</style>
